package com.tau.iplayer.client.models;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.gadgets.client.gwtrpc.GadgetsGwtRpc;
import com.google.gwt.gadgets.client.osapi.people.Person;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.tau.iplayer.client.DataStoreService;
import com.tau.iplayer.client.DataStoreServiceAsync;
import com.tau.iplayer.client.IPlayer;

public class Playlist implements Serializable, Comparable<Playlist> {

	private String name;
	private Long id;
	private List<Track> tracks;
	private Track currentTrack;
	private Track previousTrack;

	public Playlist(String name) {
		this.name = name;
	}

	public Playlist(Long id, String name) {
		this.id = id;
		this.name = name;
	}

	public Playlist() {
		this.name = null;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	public boolean equals(Playlist playlist) {
		return (this.name.equalsIgnoreCase(playlist.getName()));
	}

	/**
	 * adds a track to the playlist
	 * 
	 * @param track
	 *            the track to add
	 */
	public void addTrack(Track track) {
		if (tracks == null) {
			tracks = new ArrayList<Track>();
		}
		tracks.add(track);
	}

	/**
	 * @return the tracks
	 */
	public List<Track> getTracks() {
		return tracks;
	}

	/**
	 * @param tracks
	 *            the tracks to set
	 */
	public void setTracks(List<Track> tracks) {
		this.tracks = tracks;
	}

	/**
	 * 
	 * @return true if the playlist is empty
	 */
	public boolean isEmpty() {
		return (tracks == null || tracks.isEmpty());
	}

	/**
	 * loads this playlist tracks
	 */
	public void loadTracks(Person viewer) {
		DataStoreServiceAsync dataStoreService = GWT
				.create(DataStoreService.class);
		GadgetsGwtRpc.redirectThroughProxy((ServiceDefTarget) dataStoreService);
		dataStoreService.getTracks(viewer.getId(), this, new AsyncCallback<List<Track>>() {

			@Override
			public void onSuccess(List<Track> result) {
				Collections.sort(result);
				tracks = result;
			}

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub

			}
		});
	}

	/**
	 * loads this playlist tracks
	 */
	public void loadTracks(final IPlayer iPlayer) {
		DataStoreServiceAsync dataStoreService = GWT
				.create(DataStoreService.class);
		GadgetsGwtRpc.redirectThroughProxy((ServiceDefTarget) dataStoreService);
		dataStoreService.getTracks(iPlayer.getViewer().getId(), this, new AsyncCallback<List<Track>>() {

			@Override
			public void onSuccess(List<Track> result) {
				Collections.sort(result);
				tracks = result;
				if (iPlayer.getCurrentPlaylist().equals(Playlist.this)) {
					iPlayer.createPlaylistTable(iPlayer.getPlaylistTable(),
							Playlist.this);
				}
			}

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub

			}
		});
	}

	/**
	 * returns the next following track
	 * @param isRepeat 
	 * 
	 * @return the next track or null if no next track exists
	 */
	private Track getRegularNextTrack(boolean isRepeat) {
		if (tracks != null && !tracks.isEmpty()) {
			Integer currentTrackIndex;
			if (currentTrack  == null) {
				currentTrackIndex = 0;
			} else {
				currentTrackIndex = tracks.indexOf(currentTrack);
				previousTrack = currentTrack;
				currentTrackIndex++;
				if(isRepeat) {
					currentTrackIndex = currentTrackIndex % tracks.size();
				}
			}
			try {
				currentTrack = tracks.get(currentTrackIndex);
			} catch (IndexOutOfBoundsException e) {
				return null;
			}
		}
		return currentTrack;
	}

	/**
	 * gets the next random track
	 * 
	 * @return the next random track
	 */
	private Track getRandomNextTrack() {
		int currentTrackIndex = -1;
		if (tracks != null && !tracks.isEmpty()) {
			previousTrack = currentTrack;
			currentTrackIndex  = Math.round((float) (Math.random())
					* (tracks.size() - 1));
		}
		currentTrack = tracks.get(currentTrackIndex);
		return currentTrack;
	}
	
	/**
	 * return the next track in the playlist
	 * @param isRandom true iff the next track should be chosen in random
	 * @param isRepeat 
	 * @return the next track
	 */
	public Track getNextTrack(boolean isRandom, boolean isRepeat) {
		Track nextTrack = (isRandom) ? getRandomNextTrack() : getRegularNextTrack(isRepeat);
		return nextTrack;
	}

//	/**
//	 * gets the previous track
//	 * 
//	 * @return the previous track or null if no such track exists
//	 */
//	public Track getRandomPreviousTrack() {
//		if (previousTrackIndex != null) {
//			currentTrackIndex = previousTrackIndex;
//			return tracks.get(previousTrackIndex);
//		} else {
//			return null;
//		}
//	}

	public Track getPreviousTrack() {
		if (tracks != null && !tracks.isEmpty()) {
			int currentTrackIndex = -1;
			if (currentTrack == null) {
				previousTrack = null;
			} else {
				previousTrack = currentTrack;
				currentTrackIndex  = tracks.indexOf(currentTrack) - 1;
			}
			try {
				currentTrack = tracks.get(currentTrackIndex);
			} catch (IndexOutOfBoundsException e) {
				return null;
			}
		}
		return currentTrack;
	}

	/**
	 * sets the current track
	 * 
	 * @param track
	 *            the track to set
	 */
	public void setCurrentTrack(Track track) {
		previousTrack = currentTrack;
		currentTrack = track;
	}
	
	/**
	 * 
	 * @return the current track index
	 */
	public Integer getCurrentTrackIndex() {
		return tracks.indexOf(currentTrack);
	}

	/**
	 * @return the previousTrackIndex
	 */
	public Integer getPreviousTrackIndex() {
		return tracks.indexOf(previousTrack);
	}

	@Override
	public int compareTo(Playlist o) {
		return this.getName().compareTo(o.getName());
	}

	/**
	 * @return the id
	 */
	public Long getId() {
		return id;
	}
	
	public void reset() {
		this.currentTrack = null;
		this.previousTrack = null;
	}

	public boolean isFirstPlayedTrack(Track track) {
		return (tracks.contains(track) && previousTrack == null);
	}
}
